package org.csu.demo.nio_chat.server;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.charset.Charset;
import java.util.Iterator;
import java.util.Set;

public class ChatServer {

    //服务端启动的方法
    public void startServer() throws IOException {
        //1.创建Selector选择器
        Selector selector = Selector.open();

        //2.创建SelectorSocketChannel通道
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        //3.为Channel绑定监听端口
        serverSocketChannel.bind(new InetSocketAddress(83));
        serverSocketChannel.configureBlocking(false);//设置为非阻塞模式
        //4.循环等待连接接入
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);//注册channel通道到选择器上
        System.out.println("服务器启动成功");

        for (;;) {
            int readChannels = selector.select();//获取Channel数量
            if (readChannels == 0) {//没有可用
                continue;
            }

            Set<SelectionKey> selectionKeys = selector.selectedKeys();//获取可用的channel
            //遍历
            Iterator<SelectionKey> iterator = selectionKeys.iterator();
            while (iterator.hasNext()) {
                SelectionKey selectionKey = iterator.next();

                iterator.remove();//移除set集合当前的selectionKey

                //5.根据状态调用不同方法完成业务
                //accept状态
                if (selectionKey.isAcceptable()) {
                    acceptOperator(serverSocketChannel, selector);
                }
                //可读状态
                if (selectionKey.isReadable()) {
                    try {
                        readOperator(selector, selectionKey);
                    } catch (IOException e) {
                        // 处理客户端异常关闭连接的情况
                        System.out.println("客户端连接关闭: " + ((SocketChannel) selectionKey.channel()).getRemoteAddress());
                        selectionKey.cancel();
                        try {
                            selectionKey.channel().close();
                        } catch (IOException ex) {
                            ex.printStackTrace();
                        }
                    }
                }
            }
        }
    }

    //处理可读状态
    private void readOperator(Selector selector, SelectionKey selectionKey) throws IOException {
        //1.从SelectionKey获取已经就绪的通道
        SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
        //2.创建buffer
        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
        //3.循环读取客户端信息
        int readLength = socketChannel.read(byteBuffer);
        String message = "";
        if (readLength > 0) {
            byteBuffer.flip();//切换为读模式
            //下面读取内容
            message += Charset.forName("UTF-8").decode(byteBuffer);
        }
        //4.将channel再注册到选择器上，监听可读
        socketChannel.register(selector, SelectionKey.OP_READ);
        //5.将客户端发送的消息广播
        if (message.length() > 0) {
            System.out.println(message);//广播出去
            castOtherClient(message, selector, socketChannel);
        }
    }

    //广播方法
    private void castOtherClient(String message, Selector selector, SocketChannel socketChannel) throws IOException {
        // 排除欢迎消息不进行广播
        if ("welcome to the chat server!".equals(message.trim())) {
            return;
        }
        //1.获取所有接入的用户端
        Set<SelectionKey> selectionKeySet = selector.keys();
        //2.循环所有channel广播消息
        for (SelectionKey selectionKey : selectionKeySet) {
            //获取每个channel
            Channel tarChannel = selectionKey.channel();
            //注意剔除自己
            if (tarChannel instanceof SocketChannel && socketChannel != tarChannel) {
                try {
                    ((SocketChannel) tarChannel).write(Charset.forName("UTF-8").encode(message));
                } catch (IOException e) {
                    // 处理广播时客户端连接异常的情况
                    System.out.println("广播消息时客户端连接异常: " + ((SocketChannel) tarChannel).getRemoteAddress());
                    selectionKey.cancel();
                    tarChannel.close();
                }
            }
        }
    }

    //处理接入（accept）状态
    private void acceptOperator(ServerSocketChannel serverSocketChannel, Selector selector) throws IOException {
        //1.创建socketChannel
        SocketChannel socketChannel = serverSocketChannel.accept();
        //2.把socketChannel设置为非阻塞
        socketChannel.configureBlocking(false);

        //3.注册到选择器、监听可读状态
        socketChannel.register(selector, SelectionKey.OP_READ);

        //4.回复客户端
        socketChannel.write(Charset.forName("UTF-8")
                .encode("welcome to the chat server!"));
    }

    //主方法
    public static void main(String[] args) {
        try {
            new ChatServer().startServer();
        } catch (IOException e) {
            //throw new RuntimeException(e);
            e.printStackTrace();
        }
    }
}